using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;

namespace HWEngine
{
	[Serializable]
	public class Letter: IComparable<Letter>
	{
		private float _scaleX = 1;
		private float _scaleY = 1;
		private float _shiftX;
		private float _shiftY;

		[XmlArrayItem(ElementName = "Line")]
		public List<Line> Lines { get; set; }

		[XmlAttribute("Key")]
		public string Key { get; set; }

		[XmlAttribute("Width")]
		public float Width { get; set; }

		[XmlAttribute("SystemLetter")]
		public bool SystemLetter { get; set; }

		public float RealWidth
		{
			get { return _scaleX * Width; }
		}

		public float RealHeight
		{
			get { return _scaleY; }
		}

		[XmlIgnore]
		public bool ChangedLines { get; set; }

		public String Caption
		{
			get
			{
				if (Key.Length > 1)
				{
					return Key;
				}
				if (Key.Length == 1)
				{
					return String.Format("{0} ({1})", Key, (int)Key[0]);
				}
				return string.Empty;
			}
		}

		public override string ToString()
		{
			return string.Format("Letter '{0}'", Key);
		}

		public Letter()
		{
			Lines = new List<Line>();
		}

		public Letter Clone()
		{
			var l = new Letter {Key = Key, Width = Width, SystemLetter = SystemLetter};
			SetShift(0, 0);
			SetScale(1, 1);
			foreach (var line in this.Lines)
			{
				l.Lines.Add(line.Clone());
			}
			return l;
		}

		public void SetShift(float X, float Y)
		{
			Shift(-_shiftX, -_shiftY);
			_shiftX = X;
			_shiftY = Y;
			Shift(_shiftX, _shiftY);
		}

		public void Shift(float xoffset, float yoffset)
		{
			foreach (Line line in Lines)
			{
				line.Shift(xoffset, yoffset);
			}
		}

		public void SetScale(float X, float Y)
		{
			if (_scaleX == X && _scaleY == Y)
			{
				return;
			}

			float oldShiftX = _shiftX;
			float oldShiftY = _shiftY;
			SetShift(0, 0);
			Scale(X/_scaleX, Y/_scaleY);
			_scaleX = X;
			_scaleY = Y;
			SetShift(oldShiftX, oldShiftY);
		}

		public void Scale(float X, float Y)
		{
			foreach (Line line in Lines)
			{
				line.Scale(X, Y);
			}
		}

		public void SetColor(Color color)
		{
			foreach (Line line in Lines)
			{
				line.Color = color;
			}
		}

		public void SetLineWidth(float value)
		{
			foreach (Line line in Lines)
			{
				line.Width = value;
			}
		}

		public int CompareTo(Letter other)
		{
			return string.Compare(Key, other.Key);
		}

		public Line GetStartLine()
		{
			foreach (Line l in Lines)
			{
				if (l.StartIndex >= 0 && l.StartConcatMode != ConcatMode.None)
				{
					return l;
				}
			}
			return null;
		}

		public Line GetFinishLine()
		{
			foreach (Line l in Lines)
			{
				if (l.FinishIndex >= 0 && l.FinishConcatMode != ConcatMode.None)
				{
					return l;
				}
			}
			return null;
		}

		public void ResetFinish()
		{
			Line l = GetFinishLine();
			if (l != null)
			{
				l.FinishIndex = -1;
				l.FinishConcatMode = ConcatMode.None;
			}
		}

		public void ResetStart()
		{
			Line l = GetStartLine();
			if (l != null)
			{
				l.StartIndex = -1;
				l.StartConcatMode = ConcatMode.None;
			}
		}

		public PointF GetCenterPoint()
		{
			float dx = Lines.Aggregate(0f, (ax, l) => (ax + l.Points.Aggregate(0f, (bx, p) => (p.X + bx) / 2f)) / 2f);
			float dy = Lines.Aggregate(0f, (ay, l) => (ay + l.Points.Aggregate(0f, (by, p) => (p.Y + by) / 2f)) / 2f);
			return new PointF(dx, dy);
		}
	}
}